
#include "lib.h"

__declspec(naked) void
CFrameBitmapBlast(char *pDest, char *pSrc, long height, long width,
	long NextDestLine, long NextSrcLine)
{
	__asm
	{
		; prologue
		push	ebp
		mov		ebp, esp
		sub		esp, __LOCAL_SIZE

		push	ecx
		push	edi
		push	esi

		mov		edi,8[ebp]			; pDest
		mov		esi,12[ebp]			; pSrc

		cld
		jmp		FBYLoop

FBXLoop:
		mov		ecx,20[ebp]			; move dwords
		sar		ecx,1
		rep		movsd

		mov		ecx,20[ebp]			; finish any extra bytes
		and		ecx,01h
		rep		movsw

		add		edi,24[ebp]			; pDest += NextDestLine
		add		esi,28[ebp]			; pSrc += NextSrcLine

FBYLoop:
		dec		DWORD PTR 16[ebp]
		jge		FBXLoop

		pop		esi
		pop		edi
		pop		ecx

		; epilogue
		mov		esp, ebp
		pop		ebp

		ret
	}

}

/*
__declspec(naked) void
CFrameTransBitmapBlast(char *pDest, char *pSrc,
	long height, long width, long NextDestLine, long NextSrcLine)
{
//	CFrameBitmapBlast(pDest, pSrc, height, width, NextDestLine, NextSrcLine);

	static unsigned short tColor;

	tColor = (unsigned short)getTransparentColor ();

	__asm
	{
		; prologue
		push	ebp
		mov		ebp, esp
		sub		esp, __LOCAL_SIZE

		test	DWORD PTR 20[ebp],0ffffffffh	; width
		je		FBTAbort

		push	ebx
		push	ecx
		push	edi
		push	esi

		mov		edi,8[ebp]			; pDest
		mov		esi,12[ebp]			; pSrc

		cld

		mov		bx,tColor

		jmp		FBTYLoop

FBTXLoop:
		mov		ecx,20[ebp]			; width

NextPixel:
		mov		ax,[esi]
		cmp		ax,bx
		jz		SkipPixel
		mov		[edi],ax
SkipPixel:		
		add		edi,2
		add		esi,2
		loop	NextPixel

		add		edi,24[ebp]			; pDest += NextDestLine
		add		esi,28[ebp]			; pSrc += NextSrcLine

FBTYLoop:
		dec		DWORD PTR 16[ebp]
		jge		FBTXLoop

		pop		esi
		pop		edi
		pop		ecx
		pop		ebx

FBTAbort:
		; epilogue
		mov		esp, ebp
		pop		ebp

		ret
	}

}
*/

__declspec(naked) void
CFrameTransBitmapBlast(char *pDest, char *pSrc,
	long height, long width, long NextDestLine, long NextSrcLine)
{
//	CFrameBitmapBlast(pDest, pSrc, height, width, NextDestLine, NextSrcLine);

	static unsigned long	tmp;
	static unsigned short tColor;

	tColor = (unsigned short)getTransparentColor ();

	__asm
	{
		; prologue
		push	ebp
		mov		ebp, esp
		sub		esp, __LOCAL_SIZE

		test	DWORD PTR 20[ebp],0ffffffffh	; width
		je		FBTAbort

		push	ebx
		push	ecx
		push	edx
		push	edi
		push	esi

		mov		edi,8[ebp]			; pDest
		mov		esi,12[ebp]			; pSrc

		cld

		xor		eax,eax
		mov		ax,[tColor]

		jmp		FBTYLoop

FBTXLoop:
		mov		ecx,20[ebp]			; width

FBTScan:
		mov		tmp,edi
		mov		edi,esi

		repe	scasw				; count trans bytes
		je		FBTAllTrans

		inc		ecx					; always advances one too far
;		dec		edi
		sub		edi,2				; -2 because we are WORD aligned

FBTAllTrans:
		mov		ebx,edi				; remember trans count
		sub		ebx,esi

		mov		edx,ecx
		repne	scasw				; count non-trans bytes
		jne		FBRestNonTrans

		inc		ecx
FBRestNonTrans:
		mov		edi,tmp				; adjust dest by trans
		add		edi,ebx
		add		esi,ebx				; ...and src

		xchg	ecx,edx
		sub		ecx,edx
		mov		tmp,ecx
		sar		ecx,1
		rep		movsd				; copy non-trans dwords

		mov		ecx,tmp				; finish any extra bytes
		and		ecx,01h
		rep		movsw

		mov		ecx,edx
		test	ecx,ecx
		jnz		FBTScan

		add		edi,24[ebp]			; pDest += NextDestLine
		add		esi,28[ebp]			; pSrc += NextSrcLine

FBTYLoop:
		dec		DWORD PTR 16[ebp]
		jge		FBTXLoop

		pop		esi
		pop		edi
		pop		edx
		pop		ecx
		pop		ebx

FBTAbort:
		; epilogue
		mov		esp, ebp
		pop		ebp

		ret
	}

}


__declspec(naked) void
CFrameTransRLEBitmapBlast(char *pDest, char *pSrc,
	long height, long width, long NextDestLine)
{
	__asm
	{
		; prologue
		push	ebp
		mov		ebp, esp
		sub		esp, __LOCAL_SIZE

		test	DWORD PTR 20[ebp],0ffffffffh	; width
		je		FBTRAbort

		push	ebx
		push	ecx
		push	edi
		push	esi

		mov		edi,8[ebp]			; pDest
		mov		esi,12[ebp]			; pSrc

		cld
		xor		eax,eax

		jmp		FBTRYLoop

FBTRXLoop:
		mov		ecx,20[ebp]			; width

FBTRScan:
		mov		al,BYTE PTR[esi]	; skip trans bytes
		inc		esi
		add		edi,eax
		sub		ecx,eax

		mov		al,BYTE PTR[esi]
		inc		esi
		mov		ebx,eax
		xchg	ecx,eax

		sar		ecx,2
		rep		movsd				; copy non-trans dwords

		mov		ecx,ebx				; finish any extra bytes
		and		ecx,03h
		rep		movsb

		xchg	ecx,eax
		sub		ecx,ebx
		jnz		FBTRScan

		add		edi,24[ebp]			; pDest += NextDestLine

FBTRYLoop:
		dec		DWORD PTR 16[ebp]
		jge		FBTRXLoop

		pop		esi
		pop		edi
		pop		ecx
		pop		ebx

FBTRAbort:
		; epilogue
		mov		esp, ebp
		pop		ebp

		ret
	}
}

COLORSIZE
FindAlphaPaletteCombination(COLORSIZE SrcIndex, COLORSIZE DstIndex, uint8 Alpha)
{
	uint8 dr, dg, db;

	Alpha = 255 - Alpha;

	if (Alpha == 0)
		return SrcIndex;

	if (Alpha == 255)
		return DstIndex;

	if (SrcIndex == DstIndex)
		return SrcIndex;

	dr = (GETR(DstIndex)   * Alpha + (255 - Alpha) * GETR(SrcIndex)) / 255;
	dg = (GETG(DstIndex) * Alpha + (255 - Alpha) * GETG(SrcIndex)) / 255;
	db = (GETB(DstIndex)  * Alpha + (255 - Alpha) * GETB(SrcIndex)) / 255;

	return GETRGB(dr, dg, db);
}

void AlphaBlast565 (unsigned short* pDest, unsigned short* pSrc, char* pAlpha, long height, long width, long nextDestLine, long nextSrcLine, long nextAlphaLine)
{
	while (height--)
	{
		int i;
		unsigned char PercentAlp;

		for (i=0; i<width; ++i)
		{
			uint8 dr, dg, db;
			//Explictly mask sign data
			PercentAlp = 255u - ((*pAlpha) & 0xFF);

			if (PercentAlp == 255 || *pSrc == *pDest || (*pDest == getTransparentColor() && PercentAlp > 128))
				; /* do nothing */
			else if (PercentAlp == 0)
				*pDest = *pSrc;
			else
			{
				if (*pDest == getTransparentColor())
				{
					*pDest = (COLORSIZE)BLACK;
				}

				dr = (R565(*pDest) * PercentAlp + (255 - PercentAlp) * R565(*pSrc)) / 255;
				dg = (G565(*pDest) * PercentAlp + (255 - PercentAlp) * G565(*pSrc)) / 255;
				db = (B565(*pDest) * PercentAlp + (255 - PercentAlp) * B565(*pSrc)) / 255;

				*pDest = RGB565(dr, dg, db);
			}

			pSrc++;
			pDest++;
			pAlpha++;
		}
		pSrc += nextSrcLine;
		pDest += nextDestLine;
		pAlpha += nextAlphaLine;
	}
}

void AlphaBlast555 (unsigned short* pDest, unsigned short* pSrc, char* pAlpha, long height, long width, long nextDestLine, long nextSrcLine, long nextAlphaLine)
{
	while (height--)
	{
		int i;
		unsigned char PercentAlp;

		for (i=0; i<width; ++i)
		{
			uint8 dr, dg, db;

			PercentAlp = 255 - (*pAlpha);

			if (PercentAlp == 255 || *pSrc == *pDest || (*pDest == getTransparentColor() && PercentAlp > 128))
				; /* do nothing */
			else if (PercentAlp == 0)
				*pDest = *pSrc;
			else
			{
				if (*pDest == getTransparentColor())
				{
					*pDest = (COLORSIZE)BLACK;
				}

				dr = (R555(*pDest)   * PercentAlp + (255 - PercentAlp) * R555(*pSrc)) / 255;
				dg = (G555(*pDest) * PercentAlp + (255 - PercentAlp) * G555(*pSrc)) / 255;
				db = (B555(*pDest)  * PercentAlp + (255 - PercentAlp) * B555(*pSrc)) / 255;

				*pDest = RGB555(dr, dg, db);
			}

			pSrc++;
			pDest++;
			pAlpha++;
		}
		pSrc += nextSrcLine;
		pDest += nextDestLine;
		pAlpha += nextAlphaLine;
	}
}

// Alpha blending with per-pixel alpha value
void CFrameAlphaBitmapBlast (unsigned short* pDest, unsigned short* pSrc, char* pAlpha, long height, long width, long nextDestLine, long nextSrcLine, long nextAlphaLine)
{
	if (getImageFormat ())
		AlphaBlast555 (pDest, pSrc, pAlpha, height, width, nextDestLine, nextSrcLine, nextAlphaLine);
	else
		AlphaBlast565 (pDest, pSrc, pAlpha, height, width, nextDestLine, nextSrcLine, nextAlphaLine);
}



void CAlphaBlast565 (unsigned short* pDest, unsigned short* pSrc, uint8 Alpha, long height, long width, long nextDestLine, long nextSrcLine)
{
	int i;
	uint8 Alpha2;
	unsigned short tColor;

	tColor = (unsigned short)getTransparentColor ();
	Alpha2 = 255 - Alpha;

	while (height--)
	{
		for (i=0; i<width; ++i)
		{
			uint8 dr, dg, db;

			if (*pSrc == tColor || Alpha == 255 || *pSrc == *pDest)
				; /* do nothing */
			else if (Alpha == 0)
				*pDest = *pSrc;
			else
			{
				dr = (R565(*pDest) * Alpha + Alpha2 * R565(*pSrc)) / 255;
				dg = (G565(*pDest) * Alpha + Alpha2 * G565(*pSrc)) / 255;
				db = (B565(*pDest) * Alpha + Alpha2 * B565(*pSrc)) / 255;

				*pDest = RGB565(dr, dg, db);
			}

			pSrc++;
			pDest++;
		}
		pSrc += nextSrcLine;
		pDest += nextDestLine;
	}
}

void CAlphaBlast555 (unsigned short* pDest, unsigned short* pSrc, uint8 Alpha, long height, long width, long nextDestLine, long nextSrcLine)
{
	int i;
	uint8 Alpha2;
	unsigned short tColor;

	tColor = (unsigned short)getTransparentColor ();
	Alpha2 = 255 - Alpha;

	while (height--)
	{
		for (i=0; i<width; ++i)
		{
			uint8 dr, dg, db;

			if (*pSrc == tColor || Alpha == 255 || *pSrc == *pDest)
				; /* do nothing */
			else if (Alpha == 0)
				*pDest = *pSrc;
			else
			{
				dr = (R555(*pDest) * Alpha + Alpha2 * R555(*pSrc)) / 255;
				dg = (G555(*pDest) * Alpha + Alpha2 * G555(*pSrc)) / 255;
				db = (B555(*pDest) * Alpha + Alpha2 * B555(*pSrc)) / 255;

				*pDest = RGB555(dr, dg, db);
			}

			pSrc++;
			pDest++;
		}
		pSrc += nextSrcLine;
		pDest += nextDestLine;
	}
}



// Alpha blending with constant alpha value.
void AlphaBitmapBlast (unsigned short* pDest, unsigned short* pSrc, uint8 Alpha, long height, long width, long nextDestLine, long nextSrcLine)
{
	nextSrcLine >>= 1;
	nextDestLine >>= 1;

	if (getImageFormat ())
		CAlphaBlast555 (pDest, pSrc, Alpha, height, width, nextDestLine, nextSrcLine);
	else
		CAlphaBlast565 (pDest, pSrc, Alpha, height, width, nextDestLine, nextSrcLine);
}

